{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "54b1cd7d-e884-4d74-8a49-0fcdffdd3f30",
   "metadata": {},
   "source": [
    "# Risk-Neutral Valuation and Numerical Methods"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0bfc0241-b312-45cd-b1b6-cfecab9ad85e",
   "metadata": {},
   "source": [
    "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d0d0add-ff03-4c37-af3c-3942c8adc582",
   "metadata": {
    "tags": []
   },
   "source": [
    "## Load the Libs we need"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "4b0d19b3-7892-470c-8051-b3460605ed1a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# import Lib\n",
    "import pandas as pd\n",
    "import datetime as dt\n",
    "import pytz\n",
    "import os\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import yfinance as yf\n",
    "import scipy.stats as si\n",
    "import math\n",
    "import networkx as nx\n",
    "\n",
    "# import module\n",
    "from datetime import datetime, timezone\n",
    "from datetime import date, time\n",
    "from math import trunc\n",
    "from dateutil.parser import parse"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5649334c-a1a9-49f1-ab39-dff1bea2b512",
   "metadata": {},
   "source": [
    "## Implementing numerical methods for options pricing in Python"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b58d17c4-3096-4e08-bd33-3164b782815e",
   "metadata": {},
   "source": [
    "#### Constructing the Crank-Nicolson Scheme"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "bd31b931-5b26-4032-b510-c266f6ae3ca0",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The European call option price is: $23.24\n",
      "The European put option price is: $8.14\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from scipy.linalg import solve\n",
    "\n",
    "# Parameters\n",
    "S_max = 300\n",
    "K = 145\n",
    "r = 0.05\n",
    "sigma = 0.2\n",
    "T = 1\n",
    "N_S = 100\n",
    "N_T = 1000\n",
    "dt = T / N_T\n",
    "ds = S_max / N_S\n",
    "\n",
    "# Set up A and B matrices\n",
    "A = np.zeros((N_S - 2, N_S - 2))\n",
    "B = np.zeros((N_S - 2, N_S - 2))\n",
    "\n",
    "for i in range(1, N_S - 1):\n",
    "    j = i - 1\n",
    "    A[j, j] = 1 + dt * (sigma**2 * i**2 + r)\n",
    "    B[j, j] = 1 - dt * (sigma**2 * i**2 + r)\n",
    "    if i > 1:\n",
    "        A[j, j - 1] = -0.5 * dt * (sigma**2 * i**2 - r * i)\n",
    "        B[j, j - 1] = 0.5 * dt * (sigma**2 * i**2 - r * i)\n",
    "    if i < N_S - 2:\n",
    "        A[j, j + 1] = -0.5 * dt * (sigma**2 * i**2 + r * i)\n",
    "        B[j, j + 1] = 0.5 * dt * (sigma**2 * i**2 + r * i)\n",
    "\n",
    "# Initial condition: payoff at maturity for a call option\n",
    "V_call = np.maximum(np.arange(0, S_max, ds) - K, 0)[1:-1]\n",
    "\n",
    "# Initial condition: payoff at maturity for a put option\n",
    "V_put = np.maximum(K - np.arange(0, S_max, ds), 0)[1:-1]\n",
    "\n",
    "# Time-stepping loop for the call option\n",
    "for t in range(N_T):\n",
    "    b_call = B @ V_call\n",
    "    # Adjust for boundary conditions if necessary\n",
    "    V_call = solve(A, b_call)\n",
    "\n",
    "# Time-stepping loop for the put option\n",
    "for t in range(N_T):\n",
    "    b_put = B @ V_put\n",
    "    # Adjust for boundary conditions if necessary\n",
    "    V_put = solve(A, b_put)\n",
    "\n",
    "# Option prices at S = $150\n",
    "call_option_price = V_call[int(150 / ds) - 1]\n",
    "put_option_price = V_put[int(150 / ds) - 1]\n",
    "\n",
    "print(f\"The European call option price is: ${call_option_price:.2f}\")\n",
    "print(f\"The European put option price is: ${put_option_price:.2f}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "05347604-d7ce-4f81-b5db-a3abfb024d37",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
